#include <glpk.h>
#include <iostream>
#include <fstream>
#include <sstream>

#include <vector>
#include <utility>

#include "warehouse.hh"

#include "variable.hh"
#include "constraint.hh"
#include "problem.hh"
#include "bound.hh"


int main(int argc, char** argv)
{
  //Check the command line
  if (argc != 2)
    {
      std::cout << "Usage : ./plam inputfile" << std::endl;
      return (1);
    }

  //Try to open the input file
  std::ifstream filein (argv[1], std::ifstream::in);
  if (!filein.is_open ())
    {
      std::cout << "Error : unable to open " << argv[1] << "." << std::endl;
      return (1);
    }
  std::cout << "-----Inputs-----" << std::endl;
  std::cout << "File selected : " << argv[1] << "." << std::endl;

  problem P = problem("warehouses");

  unsigned nb_storage;
  unsigned nb_candidates;

  //Get the info on the first line.
  filein >> nb_candidates;
  filein >> nb_storage;

  std::cout << "Number of candidates : " << nb_candidates << std::endl
  	    << "Number of storages to be build : " << nb_storage << std::endl << std::endl;

  //Read info about warehouses.
  std::vector<warehouse> warehouses;
  bound bnd (0, 1);
  objective_function obj = objective_function (objective_function::MAX);

  for (unsigned i = 1; i <= nb_candidates; ++i)
    {
      unsigned id, c;
      int x, y;

      filein >> id;
      filein >> x;
      filein >> y;
      filein >> c;

      warehouses.push_back (warehouse (id, x, y, c));
      std::ostringstream name;
      name << "x" << id;
      variable var = variable (name.str (), variable::Binary, bnd);

      P.add (var);
      obj.add_variable (P.var(name.str ()), c);
    }


  P.add (obj);

  //Check the warehouses that are more than 50kms away.
  std::vector<std::pair<unsigned, unsigned> > not_ok;

  for (unsigned i = 1; i <= nb_candidates; ++i)
    for (unsigned j = i + 1; j <= nb_candidates; ++j)
      {
  	if (warehouses[i - 1].dist (warehouses[j - 1]) > 50)
  	  { // i - 1 and j - 1 in conflict
	    std::ostringstream name;
	    name << "d_" << i << "_" << j;
	    constraint cons = constraint (name.str (), bnd);
	    std::ostringstream vi, vj;
	    vi << "x" << i;
	    vj << "x" << j;

	    

	    cons.add_variable (P.var (vi.str ()), 1);
	    cons.add_variable (P.var (vj.str ()), 1);

	    P.add(cons);
  	  }
      }

  bound bnd_m = bound (bound::FIXED, nb_storage);
  constraint cons = constraint ("nb_w", bnd_m);
  for (unsigned i = 1; i <= nb_candidates; ++i)
    {
       std::ostringstream vi;
       vi << "x" << i;
       cons.add_variable (P.var (vi.str ()), 1);
    }

  P.add (cons);

  std::cout << "-----Problem------" << std::endl;
  std::cout << P << std::endl;
  
  P.run();

  std::cout << std::endl << "-----Results-----" << std::endl;

  P.display_result();
  
  return 0;
}
